/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package network;

import controllers.DatabaseController;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import util.CompleteFile;
import util.IncompleteFile;
import util.PartDownload;

/**
 *
 * @author gravena
 */
public class FileRequestHandler implements Runnable {

    private Socket conn;
    private final DatabaseController dbController;

    public FileRequestHandler(Socket conn, DatabaseController dbController) {
        this.conn = conn;
        this.dbController = dbController;
    }

    @Override
    public void run() {
        try {            
            DataInputStream input = new DataInputStream(this.conn.getInputStream());
            DataOutputStream output = new DataOutputStream(this.conn.getOutputStream());

            // Receiving the UUID and the index position
            byte[] hashMD5 = new byte[16];
            //input.read(hashMD5, 0, hashMD5.length);
            PartDownload.transfer(input, hashMD5, hashMD5.length);
            long index = input.readLong();            
            
            System.out.println("[" + index + "] " + "Requisição de " + conn.getInetAddress() + " recebida.");
            
            CompleteFile file;
            synchronized(this.dbController) {
                file = dbController.searchLocalFile(hashMD5);
            }
            if (file == null) {
                output.writeBoolean(false);
                throw new IOException("Arquivo não existe localmente");
            }
            
            FileInputStream fileInput;
            
            if(!file.isComplete()) {
                java.io.File partFile = new File(dbController.SHARED_FOLDER_PATH + "/temp/" +"part" + index + file.getName());
                
                if(!partFile.exists()) {
                    output.writeBoolean(false);
                    throw new IOException("A parte requerida do arquivo não existe localmente.");
                }
                output.writeBoolean(true);
                System.out.println("[" + index + "] " + "Abrindo arquivo parcial " + partFile.getName() + "...");
                fileInput = new FileInputStream(partFile);
            } else {

                output.writeBoolean(true);
                System.out.println("[" + index + "] " + "Abrindo arquivo " + file.getName() + "...");
            
                fileInput = new FileInputStream(file.getName());                           
            
                fileInput.skip(index*IncompleteFile.CHUNK_SIZE);
            }
            
            byte[] fileBuffer = new byte[IncompleteFile.CHUNK_SIZE];
            System.out.println("[" + index + "] " + "Writing chunk to the buffer...");            
            fileInput.read(fileBuffer, 0, fileBuffer.length);                                    
            
            System.out.println("[" + index + "] " + "Sending payload...");
            output.write(fileBuffer);                        
            System.out.println("[" + index + "] " + "Payload sent...");

            fileInput.close();
            input.close();
            output.close();
            conn.close();
        } catch (IOException ex) {
            System.err.println("Erro na criação do input stream.");
            System.err.println(ex.getMessage());            
        }
    }

    public String printHashMD5(byte[] hash) {
        StringBuilder hexString = new StringBuilder();                

        for (int i = 0; i < hash.length; i++) {
            if ((0xff & hash[i]) < 0x10) {
                hexString.append("0"
                        + Integer.toHexString((0xFF & hash[i])));
            } else {
                hexString.append(Integer.toHexString(0xFF & hash[i]));
            }
        }
        
        return hexString.toString();
    }
}
